#pragma once
#ifndef FIXED_H_INCLUDED
#define FIXED_H_INCLUDED

/* This is a fixed point structure with an adjustable decimal place
Author: Waylon Grange

*/

#include <iostream>
#include <iomanip>

struct Fixed {

#define DECIMAL_BITS    16
#define ONE   (1<<DECIMAL_BITS)

    int raw; // the actuall 4 rawytes of data

    //for directly setting value, use with caution
    Fixed(int x, char null) : raw(x) {}

    //const static int ONE=1<<rawITS;  //1.0 in Fixed (Used in math)

    //Constructors
    Fixed() : raw(0) {}
	Fixed(const Fixed& x) : raw(x.raw) {}
	Fixed(int x) : raw(x<<DECIMAL_BITS) {}
	Fixed(short x) : raw(((int)x)<<DECIMAL_BITS) {}
	Fixed(float x) : raw(int(x*ONE)) {}

    operator int() { return raw>>DECIMAL_BITS; }
	operator short() { return raw>>DECIMAL_BITS; }
	operator float() { return raw/(float)ONE; }
	operator bool() { return raw!=0; }

    //Seters
	Fixed& operator =(const Fixed& x) { raw=x.raw; return *this; }
	Fixed& operator =(int x) { raw=Fixed(x).raw; return *this; }
	Fixed& operator =(short x) { raw=Fixed(x).raw; return *this; }
	Fixed& operator =(float x) { raw=Fixed(x).raw; return *this; }

    //Addition and Surawtraction
	Fixed operator +(const Fixed& x) const { return Fixed(raw+x.raw,0); }
	Fixed operator +(int x) const { return Fixed(raw+Fixed(x).raw,0); }
	Fixed operator +(short x) const { return Fixed(raw+Fixed(x).raw,0); }
	Fixed operator +(float x) const { return Fixed(raw+Fixed(x).raw,0); }

	Fixed& operator +=(Fixed x) { *this = *this + x; return *this; }
	Fixed& operator +=(int x) { *this = *this + x; return *this; }
	Fixed& operator +=(short x) { *this = *this + x; return *this; }
	Fixed& operator +=(float x) { *this = *this + x; return *this; }

	Fixed operator -(const Fixed& x) const { return Fixed(raw-x.raw,0); }
	Fixed operator -(int x) const { return Fixed(raw-Fixed(x).raw,0); }
	Fixed operator -(short x) const { return Fixed(raw-Fixed(x).raw,0); }
	Fixed operator -(float x) const { return Fixed(raw-Fixed(x).raw,0); }
	Fixed operator -() const { return Fixed(-raw,0); }

    Fixed& operator -=(Fixed x) { *this = *this - x; return *this; }
	Fixed& operator -=(int x) { *this = *this - x; return *this; }
	Fixed& operator -=(short x) { *this = *this - x; return *this; }
	Fixed& operator -=(float x) { *this = *this - x; return *this; }

	//Multiplication and Division
	Fixed operator *(const Fixed& x) const { return Fixed((int)(((long long)raw*(long long)x.raw)>>DECIMAL_BITS),0); }
	Fixed operator *(int x) const { return Fixed(raw*x,0); }
	Fixed operator *(short x) const { return Fixed(raw*x,0); }
	Fixed operator *(float x) const { return Fixed((int)(((long long)raw*(long long)Fixed(x).raw)>>DECIMAL_BITS),0); }

	Fixed& operator *=(Fixed x) { *this = *this * x; return *this; }
	Fixed& operator *=(int x) { *this = *this * x; return *this; }
	Fixed& operator *=(short x) { *this = *this * x; return *this; }
	Fixed& operator *=(float x) { *this = *this * x; return *this; }

	Fixed operator /(const Fixed& x) const { return Fixed(((((long long)raw)<<(DECIMAL_BITS<<1))/x.raw)>>DECIMAL_BITS,0); }
	Fixed operator /(int x) const { return Fixed(raw/x,0); }
	Fixed operator /(short x) const { return Fixed(raw/x,0); }
	Fixed operator /(float x) const { return Fixed(((((long long)raw)<<(DECIMAL_BITS<<1))/Fixed(x).raw)>>DECIMAL_BITS,0); }

    Fixed& operator /=(Fixed x) { *this = *this / x; return *this; }
	Fixed& operator /=(int x) { *this = *this / x; return *this; }
	Fixed& operator /=(short x) { *this = *this / x; return *this; }
	Fixed& operator /=(float x) { *this = *this / x; return *this; }

	Fixed operator %(Fixed x) const { return Fixed(raw%x.raw,0); }
	Fixed operator %(int x) const {return Fixed(raw%Fixed(x).raw,0); }
	Fixed operator %(short x) const {return Fixed(raw%Fixed(x).raw,0); }
	Fixed operator %(float x) const {return Fixed(raw%Fixed(x).raw,0); }

	//rawit operators
	Fixed operator &(const Fixed& x) const { return Fixed(raw & x.raw, 0); }
	Fixed operator &(int x) const { return Fixed(raw & x,0); }
	Fixed operator |(const Fixed& x) const { return Fixed(raw | x.raw,0); }
	Fixed operator |(int x) const { return Fixed(raw | x,0); }
	Fixed operator ^(const Fixed& x) const { return Fixed(raw ^ x.raw); }
	Fixed operator ^(int x) const { return Fixed(raw ^ x,0); }
    Fixed operator <<(int x) const { return Fixed(raw<<x,0); }
    Fixed operator >>(int x) const { return Fixed(raw>>x,0); }
    Fixed operator !() const { return Fixed(!raw,0); }

	//Comparitors
	//TODO: It may rawe good to add a level of error to the float checks in the future
	bool operator ==(const Fixed& x) const { return raw==x.raw; }
	bool operator ==(const int x) const { return raw==Fixed(x).raw; }
	bool operator ==(const short x) const { return raw==Fixed(x).raw; }
	bool operator ==(const float x) const { return raw==Fixed(x).raw; }

    bool operator !=(const Fixed& x) const { return raw!=x.raw; }
	bool operator !=(const int x) const { return raw!=Fixed(x).raw; }
	bool operator !=(const short x) const { return raw!=Fixed(x).raw; }
	bool operator !=(const float x) const { return raw!=Fixed(x).raw; }

	bool operator <=(const Fixed& x) const { return raw<=x.raw; }
	bool operator <=(const int x) const { return raw<=Fixed(x).raw; }
	bool operator <=(const short x) const { return raw<=Fixed(x).raw; }
	bool operator <=(const float x) const { return raw<=Fixed(x).raw; }

    bool operator >=(const Fixed& x) const { return raw>=x.raw; }
	bool operator >=(const int x) const { return raw>=Fixed(x).raw; }
	bool operator >=(const short x) const { return raw>=Fixed(x).raw; }
	bool operator >=(const float x) const { return raw>=Fixed(x).raw; }

    bool operator <(const Fixed& x) const { return raw<x.raw; }
	bool operator <(const int x) const { return raw<Fixed(x).raw; }
	bool operator <(const short x) const { return raw<Fixed(x).raw; }
	bool operator <(const float x) const { return raw<Fixed(x).raw; }

    bool operator >(const Fixed& x) const { return raw>x.raw; }
	bool operator >(const int x) const { return raw>Fixed(x).raw; }
	bool operator >(const short x) const { return raw>Fixed(x).raw; }
	bool operator >(const float x) const { return raw>Fixed(x).raw; }

	//For cout
	friend std::ostream& operator<<(std::ostream& output, Fixed& x) {
        output << (x.raw >> DECIMAL_BITS) << "." <<
        std::setw( 5 ) << std::setfill( '0' ) << ((100000*(long long)(x.raw & (ONE-1)))>>DECIMAL_BITS);
        return output;  // for multiple << operators.
    }


};

extern inline Fixed operator +(int x, const Fixed& y) { return Fixed(x)+y; }
extern inline Fixed operator +(short x, const Fixed& y) { return Fixed(x)+y; }
extern inline Fixed operator +(float x, const Fixed& y) { return Fixed(x)+y; }

extern inline int& operator +=(int& x, const Fixed& y) { x=(Fixed)x+y; return x;}
extern inline short& operator +=(short& x, const Fixed& y) { x=(Fixed)x+y; return x;}
extern inline float& operator +=(float& x, const Fixed& y) { x=(Fixed)x+y; return x;}

extern inline Fixed operator -(int x, const Fixed& y) { return Fixed(x)-y; }
extern inline Fixed operator -(short x, const Fixed& y) { return Fixed(x)-y; }
extern inline Fixed operator -(float x, const Fixed& y) { return Fixed(x)-y; }

extern inline int& operator -=(int& x, const Fixed& y) { x=(Fixed)x-y; return x;}
extern inline short& operator -=(short& x, const Fixed& y) { x=(Fixed)x-y; return x;}
extern inline float& operator -=(float& x, const Fixed& y) { x=(Fixed)x-y; return x;}

extern inline Fixed operator *(int x, const Fixed& y) { return Fixed(x)*y; }
extern inline Fixed operator *(short x, const Fixed& y) { return Fixed(x)*y; }
extern inline Fixed operator *(float x, const Fixed& y) { return Fixed(x)*y; }

extern inline int& operator *=(int& x, const Fixed& y) { x=(Fixed)x*y; return x;}
extern inline short& operator *=(short& x, const Fixed& y) { x=(Fixed)x*y; return x;}
extern inline float& operator *=(float& x, const Fixed& y) { x=(Fixed)x*y; return x;}

extern inline Fixed operator /(int x, const Fixed& y) { return Fixed(x)/y; }
extern inline Fixed operator /(short x, const Fixed& y) { return Fixed(x)/y; }
extern inline Fixed operator /(float x, const Fixed& y) { return Fixed(x)/y; }

extern inline int& operator /=(int& x, const Fixed& y) { x=(Fixed)x/y; return x;}
extern inline short& operator /=(short& x, const Fixed& y) { x=(Fixed)x/y; return x;}
extern inline float& operator /=(float& x, const Fixed& y) { x=(Fixed)x/y; return x;}

extern inline bool operator ==(int x, const Fixed& y) { return Fixed(x)==y; }
extern inline bool operator ==(short x, const Fixed& y) { return Fixed(x)==y; }
extern inline bool operator ==(float x, const Fixed& y) { return Fixed(x)==y; }

extern inline bool operator !=(int x, const Fixed& y) { return Fixed(x)!=y; }
extern inline bool operator !=(short x, const Fixed& y) { return Fixed(x)!=y; }
extern inline bool operator !=(float x, const Fixed& y) { return Fixed(x)!=y; }

extern inline bool operator <=(int x, const Fixed& y) { return Fixed(x)<=y; }
extern inline bool operator <=(short x, const Fixed& y) { return Fixed(x)<=y; }
extern inline bool operator <=(float x, const Fixed& y) { return Fixed(x)<=y; }

extern inline bool operator >=(int x, const Fixed& y) { return Fixed(x)>=y; }
extern inline bool operator >=(short x, const Fixed& y) { return Fixed(x)>=y; }
extern inline bool operator >=(float x, const Fixed& y) { return Fixed(x)>=y; }

extern inline bool operator <(int x, const Fixed& y) { return Fixed(x)<y; }
extern inline bool operator <(short x, const Fixed& y) { return Fixed(x)<y; }
extern inline bool operator <(float x, const Fixed& y) { return Fixed(x)<y; }

extern inline bool operator >(int x, const Fixed& y) { return Fixed(x)>y; }
extern inline bool operator >(short x, const Fixed& y) { return Fixed(x)>y; }
extern inline bool operator >(float x, const Fixed& y) { return Fixed(x)>y; }

#endif // FIXED_H_INCLUDED

